Skip to content

feat: Apple Health integration, profile metric sync, and advanced calorie calculations#16

Open
hoveeman wants to merge 9 commits into
saksham2001:mainfrom
hoveeman:feature/apple-health
Open

feat: Apple Health integration, profile metric sync, and advanced calorie calculations#16
hoveeman wants to merge 9 commits into
saksham2001:mainfrom
hoveeman:feature/apple-health

Conversation

@hoveeman

Copy link
Copy Markdown
Contributor

This Pull Request implements Apple Health (HealthKit) integration for PulseLoop, including:

  1. Apple Health Syncing:

    • Heart rate, SpO₂, HRV, skin temperature, sleep stages, and active daily metrics are synced to HealthKit.
    • Workout sessions (including GPS route points) are exported.
    • Syncing is idempotent (prevents duplicate data entries) and automatically deducts workout calories from daily active calorie totals to prevent double-counting in the Apple Health Move ring.
    • Syncs automatically when the app is launched or foregrounded, and debounces/triggers automatically in the background when the wearable sends new records.
  2. User Profile Editor:

    • Adds an interactive Profile Card to Settings navigating to a new profile metrics editor (ProfileEditView).
    • Supports inputting Name, Age, Sex, Height, and Weight.
    • Includes a "Sync from Apple Health" button to read birthdate, biological sex, height, and weight directly from HealthKit.
    • Full support for interchangeable unit preferences (metric/imperial labels and automatic conversions).
  3. Advanced Calorie Calculations:

    • Introduces a toggle "Use Advanced Calories" in Preferences.
    • With Heart Rate: Uses the Keytel et al. Formula (incorporating heart rate, age, weight, and biological sex).
    • Without Heart Rate: Falls back to MET-based calculations (MET * Weight * Duration) with specific MET multipliers mapped to activity types.

hoveeman and others added 4 commits June 22, 2026 17:51
Brings together the working-tree integration of the imperial-units and
Apple Health feature work (matching feature/metric-imperial and
feature/apple-health) plus related model/service/view updates, so the
Enhancements branch builds and runs all features together.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@hoveeman hoveeman requested a review from saksham2001 as a code owner June 23, 2026 15:53
hoveeman and others added 2 commits June 25, 2026 10:13
… + units

Upstream independently shipped a redesigned settings tree, a per-profile
UnitsPreference + UnitsFormatter units system, and a manual-entry profile
editor (ProfileSettingsView) — all overlapping this branch. Reconciled by
adopting upstream's implementations and re-homing only the parts unique to
this PR (HealthKit sync, Apple Health profile import, advanced calories).

Units (drop the homegrown WorkoutAppGroup.useImperialUnits toggle):
- ActivityView/TodayView/VitalsView/RecordViews/Components: read upstream's
  profile `units` via UnitsFormatter (distance, pace, temperature). Distance
  trend graphs keep a units-derived numeric divisor.
- Threaded `units` through the splits UI (SplitStrip/SplitsTable/kmSplitSeconds)
  and ActivityWorkoutRow instead of the global flag.
- Kept WorkoutAppGroup.useImperialUnits ONLY as an app-group mirror for the
  Live Activity widget (can't read SwiftData) and model-layer unit labels;
  it's now written from profile.units on save and seeded at launch.

Profile editor:
- Dropped ProfileEditView + AppRoute.profileEdit in favor of upstream's
  ProfileSettingsView; ported the "Sync from Apple Health" import into it.

Advanced calories:
- Moved the "Use advanced calories" toggle into upstream's WorkoutSettingsView
  (Activity Tracking); the calorie calc still reads the same app-group key.

Activity buckets:
- Kept upstream's idempotent upsert-by-timestamp applyActivityBucket (dropped
  this branch's resetDay variant) while preserving the HealthKit
  triggerAutomaticSync hook in PulseEventBus.

Verified: clean simulator build + full test suite (144 passed) on iOS 26.5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@saksham2001

Copy link
Copy Markdown
Owner

@hoveeman have you been able to test these with any of the rings (56ff or Colmi)? It would be great if you can report your findings. Since this is a major revision we should have extensive testing. I am also going to start testing these soon.

@hoveeman

Copy link
Copy Markdown
Contributor Author

@hoveeman have you been able to test these with any of the rings (56ff or Colmi)? It would be great if you can report your findings. Since this is a major revision we should have extensive testing. I am also going to start testing these soon.

I had tested it with the 56ff ring pretty extensively and found issues with syncing and reading data but resolved all of those issues. However, I do see some of upstream has changed a bit since this PR and could do some further analysis.

…tion)

HealthSettingsSection (connection status, authorization, and 'Sync workouts history') existed but was never rendered. Add an 'Apple Health' settings row + settingsHealth route + HealthSettingsDetailView wrapper, matching the CoachSettingsDetailView idiom.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@hoveeman

Copy link
Copy Markdown
Contributor Author

@hoveeman have you been able to test these with any of the rings (56ff or Colmi)? It would be great if you can report your findings. Since this is a major revision we should have extensive testing. I am also going to start testing these soon.

I had tested it with the 56ff ring pretty extensively and found issues with syncing and reading data but resolved all of those issues. However, I do see some of upstream has changed a bit since this PR and could do some further analysis.

I have pulled your changes in and updated the PR. Appears to be working properly still. I will continue to test over the next day or two.

HealthSyncService was export-only. Add an import path so workouts logged
by other apps (Apple Watch, Whoop, Strava, …) and stored in Apple Health
appear in PulseLoop's activity/workouts section alongside natively
recorded sessions.

- importWorkouts(): query HKWorkouts over a bounded lookback, create a
  finished ActivitySession for each, pulling calories/distance/HR via the
  non-deprecated statistics(for:) API.
- Skip workouts this app wrote to Health (own HK source) to avoid a loop.
- Dedupe re-imports by HKWorkout.uuid, stored on a new optional
  ActivitySession.healthKitWorkoutID (additive → lightweight migration).
- Map HKWorkoutActivityType onto PulseLoop's canonical activity types.
- Exclude imported rows from the export path and daily-total netting (incl.
  forced re-sync) so they're never written back or double-counted.

ActivityView already @querys finished sessions, so imports surface with no
UI change. Adds a unit test for the type mapping (HKHealthStore can't be
exercised in unit tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@hoveeman hoveeman force-pushed the feature/apple-health branch from 154f883 to 6df6492 Compare June 30, 2026 14:56
These predate the workout-import change but fail the SwiftLint job (serious
violations exit non-zero even without --strict):
- HealthSettingsSection.swift: wrap two >200-char alert message strings.
- RecordViews.swift: inline a single-use local to drop the file one line under
  the 1000-line file_length limit.

No behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants